//
// Created by Administrator on 2021/8/25.
//

#include "glad/glad.h"
#include "GLFW/glfw3.h"

#include "Common.h"
#include "Shader/ShaderProgram.h"
#include "Geometry/Matrix4x4.h"

GLuint VAO;
ShaderProgram SP;
Matrix4x4 mvMatrix;
Matrix4x4 projectionMatrix;

void FrameSizeChanged(GLFWwindow* window, int w, int h);
void Init();
void ProcessInput(GLFWwindow* window);
void Draw();

int main()
{
    if(!glfwInit())
    {
        ERROR("glfwInit failed!")
        glfwTerminate();
        return -1;
    }

    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
#ifdef MAC_OS
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1);
#else
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
#endif
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
#ifdef MAC_OS
    glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE);
#endif

    GLFWwindow* window = glfwCreateWindow(ScreenWidth, ScreenHeight, "Transform Geometry", nullptr, nullptr);
    if(!window)
    {
        ERROR("glfwCreateWindow failed!")
        glfwTerminate();
        return -1;
    }
    glfwSetFramebufferSizeCallback(window, FrameSizeChanged);
    glfwMakeContextCurrent(window);

    if(!gladLoadGLLoader((GLADloadproc) glfwGetProcAddress))
    {
        ERROR("gladLoadGLLoader failed!")
        glfwDestroyWindow(window);
        glfwTerminate();
        return -1;
    }

    Init();
    while (!glfwWindowShouldClose(window))
    {
        glfwPollEvents();
        ProcessInput(window);
        Draw();
        glfwSwapBuffers(window);
    }

    glDeleteVertexArrays(1, &VAO);
    glDeleteProgram(SP.id());

    glfwDestroyWindow(window);
    glfwTerminate();

    return 0;
}

void FrameSizeChanged(GLFWwindow* window, int w, int h)
{
    glViewport(0, 0, w, h);
    float aspect = float(w) / float(h);
    float near = 0.1f;
    float far = 1000.0f;
    float n = abs(near);
    float f = abs(far);
    float fov = 50.0f;
    float t = tanf(fov * 0.5f * DEG_2_RAD) * near;
    float b = -t;
    float r = t * aspect;
    float l = -r;
    projectionMatrix = Matrix4x4(2 * n / (r - l), 0, (l + r) / (l - r), 0,
                                 0, 2 * n / (t - b), (b + t) / (b - t), 0,
                                 0, 0, (n + f) / (n - f), 2 * f * n / (n - f),
                                 0, 0, -1, 0);
}

void Init()
{
    GLuint texture;
    glGenTextures(1, &texture);
    glBindTexture(GL_TEXTURE_2D, texture);
    glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA32F, 256, 256);

    auto data = new float[256 * 256 * 4];

    glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 256, 256, GL_RGBA, GL_FLOAT, data);
    delete[] data;
}

void ProcessInput(GLFWwindow* window)
{

}

void Draw()
{
    static const GLfloat bgColor[4] = {0.2f, 0.2f, 0.2f, 1.0f};
    glClearBufferfv(GL_COLOR, 0, bgColor);
    glClearBufferfi(GL_DEPTH_STENCIL, 0, 1.0f, 0);

    // set uniforms
    SP.Use();
}